package cn.com.rpc.dispatcher;

import cn.com.common.*;
import cn.com.rpc.NettyChannel;
import cn.com.rpc.code.DecodeObject;
import cn.com.rpc.code.ZhuRongCodeC;
import cn.com.rpc.exchange.DefaultFuture;
import cn.com.rpc.handler.Handler;
import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.io.IOException;

/**
 * @author jiaming
 */
public class ClientHandler extends ChannelDuplexHandler {

    protected static final Logger log = LogManager.getLogger();

    private Handler handler;

    public ClientHandler(Handler handler) {
        this.handler = handler;
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        try {
            if (msg instanceof Request) {
                //client接收server端推送的hotkey
                Request request = (Request) msg;
                Object data = request.getData();
                if (data instanceof DecodeObject) {
                    try {
                        data = ZhuRongCodeC.decodeBody(Constant.PROTOBUF_SERIALIZE, (DecodeObject) data);
                        request.setData(data);
                        //处理hotkey
                        NettyChannel channel = NettyChannel.getChannel(ctx.channel(), new URI());
                        handler.received(channel, request);
                    } catch (IOException e) {
                        log.error(e.getMessage(), e);
                    }
                }
            } else if (msg instanceof Response) {
                DefaultFuture.receive((Response) msg);
            }
        } finally {
            NettyChannel.removeChannelIfDisconnected(ctx.channel());
        }
    }

    @Override
    public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
        super.write(ctx, msg, promise);
        boolean isRequest = msg instanceof Request;
        promise.addListener(future -> {
            try {
                if (isRequest) {
                    boolean success = future.isSuccess();
                    Request request = (Request) msg;
                    if (success) {
                        DefaultFuture.setSend(request);
                    }
                    if (!success) {
                        Response response = new Response();
                        Header header = new Header();
                        header.setId(request.getHeader().getId());
                        header.setEventType((byte) 0);
                        header.setStatus(Constant.BAD_REQUEST);
                        response.setHeader(header);
                        DefaultFuture.receive(response);
                    }
                }
            } finally {
                NettyChannel.removeChannelIfDisconnected(ctx.channel());
            }
        });
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        log.error(cause.getMessage(), cause);
        NettyChannel.removeChannelIfDisconnected(ctx.channel());
    }
}
